#include "pipeline.h"

#include <algorithm>
#include <cctype>
#include <limits>
#include <sstream>
#include <vector>

namespace cfg
{

// 可复用校验器：数值范围检查（闭区间）
class ValidatorNumberInRange : public IValidator
{
public:
    // options:
    //   path:      路径（a.b 或 /a/b）
    //   min:       最小值（可选）
    //   max:       最大值（可选）
    //   default:   默认值（可选；当缺失或类型不匹配时作为回退参与范围校验）
    // 备注：若命中值不是数值，将报 NumberExpected；若正则参数非法，将报 Other。
    void validate(const View & view,
                  const PluginOptions & options,
                  std::vector<ConfigError> & out_errors) override
    {
        auto itp = options.find("path");
        if (itp == options.end())
            return;
        const std::string & path = itp->second;

        double min_v = 0.0, max_v = 0.0;
        bool has_min = false, has_max = false;
        if (auto it = options.find("min"); it != options.end())
        {
            try
            {
                min_v = std::stod(it->second);
                has_min = true;
            }
            catch (...)
            {
            }
        }
        if (auto it = options.find("max"); it != options.end())
        {
            try
            {
                max_v = std::stod(it->second);
                has_max = true;
            }
            catch (...)
            {
            }
        }

        // 默认值：当缺失或类型不匹配时，用于回退参与范围校验
        double def_v = 0.0;
        bool has_def = false;
        if (auto it = options.find("default"); it != options.end())
        {
            try
            {
                def_v = std::stod(it->second);
                has_def = true;
            }
            catch (...)
            {
            }
        }

        auto ev = view.lookup(path);
        if (!ev)
        {
            // 若提供默认值，则以默认值参与范围校验；否则保留原行为交由 required_key 处理
            if (!has_def)
                return;
            double v = def_v;
            if (has_min && v < min_v)
            {
                out_errors.emplace_back(
                    ConfigError{Errc::OutOfRange,
                                "value below minimum",
                                std::vector<std::string>{path},
                                std::nullopt,
                                std::nullopt,
                                min_v,
                                has_max ? std::optional<double>(max_v) : std::nullopt});
            }
            if (has_max && v > max_v)
            {
                out_errors.emplace_back(
                    ConfigError{Errc::OutOfRange,
                                "value above maximum",
                                std::vector<std::string>{path},
                                std::nullopt,
                                std::nullopt,
                                has_min ? std::optional<double>(min_v) : std::nullopt,
                                max_v});
            }
            return;
        }
        auto num = ev->get_number();
        if (!num)
        {
            // 若提供默认值，则以默认值参与范围校验；否则保留原错误
            if (!has_def)
            {
                out_errors.emplace_back(
                    ConfigError{Errc::NumberExpected,
                                "number expected",
                                ev->path(),
                                std::nullopt,
                                std::nullopt,
                                has_min ? std::optional<double>(min_v) : std::nullopt,
                                has_max ? std::optional<double>(max_v) : std::nullopt});
                return;
            }
            double v = def_v;
            if (has_min && v < min_v)
            {
                out_errors.emplace_back(
                    ConfigError{Errc::OutOfRange,
                                "value below minimum",
                                ev->path(),
                                std::nullopt,
                                std::nullopt,
                                min_v,
                                has_max ? std::optional<double>(max_v) : std::nullopt});
            }
            if (has_max && v > max_v)
            {
                out_errors.emplace_back(
                    ConfigError{Errc::OutOfRange,
                                "value above maximum",
                                ev->path(),
                                std::nullopt,
                                std::nullopt,
                                has_min ? std::optional<double>(min_v) : std::nullopt,
                                max_v});
            }
            return;
        }
        double v = *num;
        if (has_min && v < min_v)
        {
            out_errors.emplace_back(
                ConfigError{Errc::OutOfRange,
                            "value below minimum",
                            ev->path(),
                            std::nullopt,
                            std::nullopt,
                            min_v,
                            has_max ? std::optional<double>(max_v) : std::nullopt});
        }
        if (has_max && v > max_v)
        {
            out_errors.emplace_back(
                ConfigError{Errc::OutOfRange,
                            "value above maximum",
                            ev->path(),
                            std::nullopt,
                            std::nullopt,
                            has_min ? std::optional<double>(min_v) : std::nullopt,
                            max_v});
        }
    }
};

// 可复用校验器：枚举集合包含
class ValidatorEnumInSet : public IValidator
{
public:
    // options:
    //   path:   路径
    //   values: 以逗号分隔的枚举值（仅支持标量：bool/int/double/string；布尔用 true/false）
    //   default: 可选默认值（当缺失或类型不匹配时用于回退参与枚举校验）
    void validate(const View & view,
                  const PluginOptions & options,
                  std::vector<ConfigError> & out_errors) override
    {
        auto itp = options.find("path");
        auto itv = options.find("values");
        if (itp == options.end() || itv == options.end())
            return;
        const std::string & path = itp->second;
        const std::string & values = itv->second;

        // 读取可选默认值
        std::string def;
        bool has_def = false;
        if (auto itd = options.find("default"); itd != options.end())
        {
            def = itd->second;
            has_def = true;
        }

        // 解析枚举集合（C++17 兼容：手动拆分并修剪空白）
        std::vector<std::string> items;
        auto is_space = [](unsigned char ch) { return std::isspace(ch); };
        std::stringstream ss(values);
        std::string token;
        while (std::getline(ss, token, ','))
        {
            auto first = std::find_if_not(token.begin(), token.end(), is_space);
            auto last = std::find_if_not(token.rbegin(), token.rend(), is_space).base();
            std::string trimmed = (first < last) ? std::string(first, last) : std::string{};
            if (!trimmed.empty())
                items.emplace_back(std::move(trimmed));
        }

        auto ev = view.lookup(path);
        if (!ev)
        {
            // 若提供默认值，则以默认值参与枚举校验；否则保留原行为交由 required_key 处理
            if (!has_def)
                return;
            bool hit_def = std::find(items.begin(), items.end(), def) != items.end();
            if (!hit_def)
            {
                ConfigError e{
                    Errc::EnumNotInSet, "value not in set", std::vector<std::string>{path}};
                e.notes = values;
                out_errors.emplace_back(std::move(e));
            }
            return;
        }

        // 最宽容地从视图取字符串化值以对比
        auto as_str = [&](const View & v) -> expected<std::string, ConfigError>
        {
            if (auto s = v.get_string())
                return *s;
            if (auto n = v.get_number())
                return std::to_string(*n);
            if (auto i = v.get_int64())
                return std::to_string(*i);
            if (auto b = v.get_bool())
                return *b ? std::string("true") : std::string("false");
            return unexpected(
                ConfigError{Errc::TypeMismatch, "unsupported type for enum", v.path()});
        };

        auto sv = as_str(*ev);
        if (!sv)
        {
            // 若提供默认值，则以默认值参与枚举校验；否则保留原错误
            if (!has_def)
            {
                out_errors.emplace_back(sv.error());
                return;
            }
            bool hit_def = std::find(items.begin(), items.end(), def) != items.end();
            if (!hit_def)
            {
                ConfigError e{Errc::EnumNotInSet, "value not in set", ev->path()};
                e.notes = values;
                out_errors.emplace_back(std::move(e));
            }
            return;
        }
        bool hit = std::find(items.begin(), items.end(), *sv) != items.end();
        if (!hit)
        {
            ConfigError e{Errc::EnumNotInSet, "value not in set", ev->path()};
            e.notes = values;
            out_errors.emplace_back(std::move(e));
        }
    }
};

// 可复用校验器：数组长度范围
class ValidatorArrayLength : public IValidator
{
public:
    // options: path, min_len, max_len
    void validate(const View & view,
                  const PluginOptions & options,
                  std::vector<ConfigError> & out_errors) override
    {
        auto itp = options.find("path");
        if (itp == options.end())
            return;
        auto ev = view.lookup(itp->second);
        if (!ev)
            return;

        auto arr = ev->array_view();
        if (!arr)
        {
            out_errors.emplace_back(ConfigError{Errc::TypeMismatch, "not an array", ev->path()});
            return;
        }
        size_t n = arr->size();
        size_t minl = 0, maxl = (std::numeric_limits<size_t>::max)();
        if (auto it = options.find("min_len"); it != options.end())
            try
            {
                minl = static_cast<size_t>(std::stoll(it->second));
            }
            catch (...)
            {
            }
        if (auto it = options.find("max_len"); it != options.end())
            try
            {
                maxl = static_cast<size_t>(std::stoll(it->second));
            }
            catch (...)
            {
            }

        if (n < minl)
            out_errors.emplace_back(
                ConfigError{Errc::OutOfRange, "array length below min", ev->path()});
        if (n > maxl)
            out_errors.emplace_back(
                ConfigError{Errc::OutOfRange, "array length above max", ev->path()});
    }
};

// 可复用校验器：对象必需键集合
class ValidatorObjectRequiredKeys : public IValidator
{
public:
    // options: path, keys (逗号分隔)
    void validate(const View & view,
                  const PluginOptions & options,
                  std::vector<ConfigError> & out_errors) override
    {
        auto itp = options.find("path");
        auto itk = options.find("keys");
        if (itp == options.end() || itk == options.end())
            return;
        auto ev = view.lookup(itp->second);
        if (!ev)
            return;

        auto obj = ev->object_view();
        if (!obj)
        {
            out_errors.emplace_back(ConfigError{Errc::TypeMismatch, "not an object", ev->path()});
            return;
        }
        // 拆分 keys（C++17 兼容：手动拆分并修剪空白）
        std::vector<std::string> required_keys;
        {
            auto is_space2 = [](unsigned char ch) { return std::isspace(ch); };
            std::stringstream ss2(itk->second);
            std::string tok2;
            while (std::getline(ss2, tok2, ','))
            {
                auto first = std::find_if_not(tok2.begin(), tok2.end(), is_space2);
                auto last = std::find_if_not(tok2.rbegin(), tok2.rend(), is_space2).base();
                std::string trimmed = (first < last) ? std::string(first, last) : std::string{};
                if (!trimmed.empty())
                    required_keys.emplace_back(std::move(trimmed));
            }
        }

        // 遍历校验
        for (const auto & k : required_keys)
        {
            if (!ev->has(k))
            {
                out_errors.emplace_back(ConfigError{
                    Errc::MissingKey, std::string("missing key '") + k + "'", ev->path()});
            }
        }
    }
};

// 可复用校验器：数值严格大于最小值（exclusiveMinimum）
class ValidatorExclusiveMinimum : public IValidator
{
public:
    // options:
    //   path:    路径（a.b 或 /a/b）
    //   minimum: 最小值（严格大于）
    void validate(const View & view,
                  const PluginOptions & options,
                  std::vector<ConfigError> & out_errors) override
    {
        auto itp = options.find("path");
        auto itm = options.find("minimum");
        if (itp == options.end() || itm == options.end())
            return;
        const std::string & path = itp->second;

        double min_v = 0.0;
        try
        {
            min_v = std::stod(itm->second);
        }
        catch (...)
        {
            // 非法最小值，忽略校验
            return;
        }

        auto ev = view.lookup(path);
        if (!ev)
            return; // 缺失交由 required_key 处理

        auto num = ev->get_number();
        if (!num)
        {
            out_errors.emplace_back(
                ConfigError{Errc::NumberExpected, "number expected", ev->path()});
            return;
        }
        if (*num <= min_v)
        {
            out_errors.emplace_back(ConfigError{Errc::OutOfRange,
                                                "value not greater than exclusive minimum",
                                                ev->path(),
                                                std::nullopt,
                                                std::nullopt,
                                                min_v,
                                                std::nullopt});
        }
    }
};

// 可复用校验器：数值严格小于最大值（exclusiveMaximum）
class ValidatorExclusiveMaximum : public IValidator
{
public:
    // options:
    //   path:    路径（a.b 或 /a/b）
    //   maximum: 最大值（严格小于）
    void validate(const View & view,
                  const PluginOptions & options,
                  std::vector<ConfigError> & out_errors) override
    {
        auto itp = options.find("path");
        auto itx = options.find("maximum");
        if (itp == options.end() || itx == options.end())
            return;
        const std::string & path = itp->second;

        double max_v = 0.0;
        try
        {
            max_v = std::stod(itx->second);
        }
        catch (...)
        {
            // 非法最大值，忽略校验
            return;
        }

        auto ev = view.lookup(path);
        if (!ev)
            return; // 缺失交由 required_key 处理

        auto num = ev->get_number();
        if (!num)
        {
            out_errors.emplace_back(
                ConfigError{Errc::NumberExpected, "number expected", ev->path()});
            return;
        }
        if (*num >= max_v)
        {
            out_errors.emplace_back(ConfigError{Errc::OutOfRange,
                                                "value not less than exclusive maximum",
                                                ev->path(),
                                                std::nullopt,
                                                std::nullopt,
                                                std::nullopt,
                                                max_v});
        }
    }
};

// 帮助：严格等价性比较（与数组去重策略一致）
static bool
value_equal_strict(const Value & a, const Value & b)
{
    if (a.index() != b.index())
        return false;
    switch (a.index())
    {
        case 0: // nullptr_t
            return true;
        case 1: // bool
            return std::get<bool>(a) == std::get<bool>(b);
        case 2: // int64_t
            return std::get<int64_t>(a) == std::get<int64_t>(b);
        case 3: // double
            return std::get<double>(a) == std::get<double>(b);
        case 4: // string
            return std::get<std::string>(a) == std::get<std::string>(b);
        case 5: // shared_ptr<const Array>
            return std::get<std::shared_ptr<const Array>>(a).get() ==
                   std::get<std::shared_ptr<const Array>>(b).get();
        case 6: // shared_ptr<const Object>
            return std::get<std::shared_ptr<const Object>>(a).get() ==
                   std::get<std::shared_ptr<const Object>>(b).get();
        default:
            return false;
    }
}

// 可复用校验器：数组元素唯一（uniqueItems）
class ValidatorUniqueItems : public IValidator
{
public:
    // options:
    //   path: 路径（数组）
    void validate(const View & view,
                  const PluginOptions & options,
                  std::vector<ConfigError> & out_errors) override
    {
        auto itp = options.find("path");
        if (itp == options.end())
            return;
        auto ev = view.lookup(itp->second);
        if (!ev)
            return;

        auto arr = ev->array_view();
        if (!arr)
        {
            out_errors.emplace_back(ConfigError{Errc::TypeMismatch, "not an array", ev->path()});
            return;
        }
        const auto & items = *arr;
        for (size_t i = 0; i < items.size(); ++i)
        {
            for (size_t j = i + 1; j < items.size(); ++j)
            {
                if (value_equal_strict(items[i], items[j]))
                {
                    ConfigError e{Errc::Other, "array items not unique", ev->path()};
                    e.notes = std::string("duplicate indices: ") + std::to_string(i) + "," +
                              std::to_string(j);
                    out_errors.emplace_back(std::move(e));
                    return; // 报告一次即可
                }
            }
        }
    }
};

// 帮助：将标量值转为字符串（用于 contains 简化对比）
static std::optional<std::string>
scalar_to_string(const Value & v)
{
    if (auto pb = std::get_if<bool>(&v))
        return *pb ? std::string("true") : std::string("false");
    if (auto pi = std::get_if<int64_t>(&v))
        return std::to_string(*pi);
    if (auto pd = std::get_if<double>(&v))
        return std::to_string(*pd);
    if (auto ps = std::get_if<std::string>(&v))
        return *ps;
    if (std::holds_alternative<std::nullptr_t>(v))
        return std::string("null");
    return std::nullopt; // array/object 不参与 contains 的字符串对比
}

// 可复用校验器：数组包含期望项（contains）
class ValidatorContains : public IValidator
{
public:
    // options:
    //   path:  路径（数组）
    //   value: 期望项（按字符串比较；数值/布尔将按字符串化对比）
    void validate(const View & view,
                  const PluginOptions & options,
                  std::vector<ConfigError> & out_errors) override
    {
        auto itp = options.find("path");
        auto itv = options.find("value");
        if (itp == options.end() || itv == options.end())
            return;
        auto ev = view.lookup(itp->second);
        if (!ev)
            return;

        auto arr = ev->array_view();
        if (!arr)
        {
            out_errors.emplace_back(ConfigError{Errc::TypeMismatch, "not an array", ev->path()});
            return;
        }
        const std::string & expected = itv->second;
        for (const auto & item : *arr)
        {
            if (auto s = scalar_to_string(item))
            {
                if (*s == expected)
                    return; // 命中则通过
            }
        }
        ConfigError e{Errc::Other, "array does not contain expected item", ev->path()};
        e.notes = expected;
        out_errors.emplace_back(std::move(e));
    }
};

// 可复用校验器：依赖必填（dependentRequired）
class ValidatorDependentRequired : public IValidator
{
public:
    // options:
    //   path:     路径（对象）
    //   key:      触发键（存在时检查依赖）
    //   requires: 逗号分隔的依赖键集合
    void validate(const View & view,
                  const PluginOptions & options,
                  std::vector<ConfigError> & out_errors) override
    {
        auto itp = options.find("path");
        auto itk = options.find("key");
        auto itr = options.find("requires");
        if (itp == options.end() || itk == options.end() || itr == options.end())
            return;

        auto ev = view.lookup(itp->second);
        if (!ev)
            return;

        auto obj = ev->object_view();
        if (!obj)
        {
            out_errors.emplace_back(ConfigError{Errc::TypeMismatch, "not an object", ev->path()});
            return;
        }

        const std::string & trigger = itk->second;
        if (!ev->has(trigger))
            return; // 触发键不存在则不进行依赖检查

        // 拆分 requires（C++17 兼容：手动拆分并修剪空白）
        std::vector<std::string> reqs;
        auto is_space = [](unsigned char ch) { return std::isspace(ch); };
        std::stringstream ss(itr->second);
        std::string tok;
        while (std::getline(ss, tok, ','))
        {
            auto first = std::find_if_not(tok.begin(), tok.end(), is_space);
            auto last = std::find_if_not(tok.rbegin(), tok.rend(), is_space).base();
            std::string trimmed = (first < last) ? std::string(first, last) : std::string{};
            if (!trimmed.empty())
                reqs.emplace_back(std::move(trimmed));
        }

        for (const auto & r : reqs)
        {
            if (!ev->has(r))
            {
                ConfigError e{Errc::MissingKey, std::string("missing key '") + r + "'", ev->path()};
                e.notes = std::string("required by '") + trigger + "'";
                out_errors.emplace_back(std::move(e));
            }
        }
    }
};

// 静态注册
REGISTER_VALIDATOR("number_in_range", ValidatorNumberInRange);
REGISTER_VALIDATOR("enum_in_set", ValidatorEnumInSet);
REGISTER_VALIDATOR("array_length", ValidatorArrayLength);
REGISTER_VALIDATOR("object_required_keys", ValidatorObjectRequiredKeys);
REGISTER_VALIDATOR("exclusive_minimum", ValidatorExclusiveMinimum);
REGISTER_VALIDATOR("exclusive_maximum", ValidatorExclusiveMaximum);
REGISTER_VALIDATOR("unique_items", ValidatorUniqueItems);
REGISTER_VALIDATOR("contains", ValidatorContains);
REGISTER_VALIDATOR("dependent_required", ValidatorDependentRequired);

} // namespace cfg
